/*
 * Copyright 2011 The Rusted Roof, LLC.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.proteusframework.platformservice.messaging;

import org.proteusframework.core.api.model.IMetadata;
import org.proteusframework.core.api.model.IObject;
import org.proteusframework.platformservice.grammar.IGrammarConsumer;
import org.proteusframework.platformservice.grammar.IllegalExpressionException;
import org.proteusframework.platformservice.lifecycle.api.ILifecycleListener;
import org.proteusframework.platformservice.persistence.api.messagebean.IMessageBeanDescriptor;

import java.util.Properties;

/**
 * Message sinks represent an endpoint for message bean delivery or message bean receipt.
 * <p/>
 * A <code>MessageSink</code> was designed to process a singular message bean class. No restriction at the framework
 * level exists per se on what that message bean can or cannot be. However, concrete providers may document specific
 * restrictions.
 * <p/>
 * Each <code>IMessageSink</code> can support a either a set of one or more subscribers, or a single message sink
 * listener, known as its model. In other words, it is possible to set a single message sink listener with no
 * subscribers, or multiple message subscribers with no message sink listener. It is not possible to support both a set
 * of subscribers model and a listener model concurrently.
 *
 * @param <T> Specific type of message bean that the message sink represents.
 */
public interface IMessageSink<T extends IMessageBean> extends IObject, IMetadata, ILifecycleListener, IGrammarConsumer
{
    /**
     * Returns a count of the number of registered subscribers.
     *
     * @return Subscriber count of 0 or more when either the model hasn't been establish or the subscriber model is in
     *         effect, or -1 if the message sink has settled on the sole registered listener model.
     */
    int countSubscribers();

    /**
     * Returns a count of the number of registered producers.
     *
     * @return Producer count
     */
    int countProducers();

    /**
     * Flag that indicates if the sink's model has been established. The model determines if either a set of one or
     * more subscribers or a sole registered listener is being managed by the sink. See the class documentation for more
     * details.
     *
     * @return true, if the model has been established for this instance
     */
    boolean hasModelBeenDefined();

    /**
     * Indicates if the message sink has a registered listener associated with it.
     *
     * @return true, if a registered listener exists
     */
    boolean hasRegisteredListener();

    /**
     * Identifies if this message sink was created to explicitly support subscribers.
     *
     * @return true, if the message sink explicitly supports only subscribers, or true if a subscriber has registered
     *         thus logically negating the ability of establishing a registered listener on the sink.
     */
    boolean supportsSubscribers();

    /**
     * Identifies if this message sink was created to explicitly support a sole registered listener and no subscribers.
     *
     * @return true, if the message sink explicitly supports only a sole registered listener, or true if a registered
     *         listener has been established, thus logically negating the ability of establishing a subscribers on the
     *         sink.
     */
    boolean supportsRegisteredListener();

    /**
     * Identifies the specific message bean class that this instance is capable of managing.
     *
     * @return Message bean class
     */
    Class<T> getMessageBeanClass();

    /**
     * Creates an <code>IMessageSinkSubscriber</code> suitable for polling and retrieving published message beans.
     *
     * @return Message sink subscriber that defines polling and message bean retrieval capabilities
     * @throws IllegalStateException if the message sink already has a registered listener
     */
    IMessageSinkSubscriber<T> createSubscriber() throws IllegalStateException;

    /**
     * Creates an <code>IMessageSinkSubscriber</code> suitable for polling and retrieving published message beans.
     *
     * @param metadata Additional metadata used to define the subscriber. Concrete providers must provide
     *                 documentation on what types of metadata the require or support.
     * @return Message sink subscriber that defines polling and message bean retrieval capabilities
     * @throws IllegalStateException if the message sink already has a registered listener
     */
    IMessageSinkSubscriber<T> createSubscriber(Properties metadata) throws IllegalStateException;

    /**
     * Creates an <code>IMessageSinkSubscriber</code> suitable for polling and retrieving published message beans that
     * pass the specified filter.
     *
     * @param messageBeanDescriptor Message bean descriptor used by the filter
     * @param filter                Expression filter used to determine which messages are forwarded to the subscriber
     * @return Message sink subscriber that defines polling and message bean retrieval capabilities
     * @throws IllegalStateException if the message sink already has a registered listener
     * @throws org.proteusframework.platformservice.grammar.IllegalExpressionException when the filter is invalid
     */
    IMessageSinkSubscriber<T> createSubscriber(IMessageBeanDescriptor messageBeanDescriptor, String filter)
            throws IllegalStateException, IllegalExpressionException;

    /**
     * Creates an <code>IMessageSinkSubscriber</code> suitable for polling and retrieving published message beans that
     * pass the specified filter.
     *
     * @param metadata              Additional metadata used to define the subscriber. Concrete providers must provide
     *                              documentation on what types of metadata the require or support.
     * @param messageBeanDescriptor Message bean descriptor used by the filter
     * @param filter                Expression filter used to determine which messages are forwarded to the subscriber
     * @return Message sink subscriber that defines polling and message bean retrieval capabilities
     * @throws IllegalStateException if the message sink already has a registered listener
     * @throws org.proteusframework.platformservice.grammar.IllegalExpressionException when the filter is invalid
     */
    IMessageSinkSubscriber<T> createSubscriber(Properties metadata,
                                               IMessageBeanDescriptor messageBeanDescriptor,
                                               String filter)
            throws IllegalStateException, IllegalExpressionException;

    /**
     * Establishes a single message sink listener who receives notification upon receipt of a new message bean into
     * the sink.
     *
     * @param listener Listener
     * @throws IllegalStateException if the message sink already has registered subscribers
     */
    void setMessageSinkListener(IMessageSinkListener<T> listener) throws IllegalStateException;

    /**
     * Establishes a single message sink listener who receives notification upon receipt of a new message bean
     * into the sink that passes the expression-based filter.
     *
     * @param listener              Listener
     * @param messageBeanDescriptor Message bean descriptor used by the filter
     * @param filter                Expression filter used to determine which messages are forwarded to the listener
     * @throws IllegalStateException if the message sink already has registered subscribers
     * @throws org.proteusframework.platformservice.grammar.IllegalExpressionException when the filter is invalid
     */
    void setMessageSinkListener(IMessageSinkListener<T> listener,
                                IMessageBeanDescriptor messageBeanDescriptor,
                                String filter) throws IllegalExpressionException;

    /**
     * Creates an <code>IMessageSinkProducer</code> suitable for polling and retrieving published message beans.
     *
     * @return Message sink producer that defines message bean publication capabilities
     */
    IMessageSinkProducer<T> createProducer();

    /**
     * Creates an <code>IMessageSinkProducer</code> suitable for polling and retrieving published message beans.
     *
     * @param metadata Additional metadata used to define the producer. Concrete providers must provide
     *                 documentation on what types of metadata the require or support.
     * @return Message sink producer that defines message bean publication capabilities
     */
    IMessageSinkProducer<T> createProducer(Properties metadata);
}
